﻿using System;
using MagicWorld.DDD.Domain.Event;
using MagicWorld.DDD.Domain.Event.Impl;
using MagicWorld.DDD.Domain.Service;
using MagicWorld.DDD.Domain.Types;
using MagicWorld.DDD.Domain.Types.Exceptions;

namespace MagicWorld.DDD.Domain.Entity
{
    public class Player : IMovable
    {
        public PlayerId Id { get; private set; }
        public string Name { get; private set; }
        public PlayerClass PlayerClass { get; private set; }
        public int EXP { get; private set; }
        public int Level { get; private set; }

        public void SetLevel(int level)
        {
            Level = level;
        }

        // 因为 Weapon 是实体类，但是 Weapon 能独立存在，Player 不是聚合根， 所以Player 只能保存WeaponId，而不能直接指向 Weapon
        public WeaponId WeaponId { get; private set; }

        public Transform Position { get; private set; } = Transform.ORIGIN;
        public Vector Velocity { get; private set; } = Vector.ZERO;

        public Player(PlayerId id, string name, PlayerClass playerClass)
        {
            Id = id;
            Name = name;
            PlayerClass = playerClass;
        }

        public void Equip(Weapon weapon, IEquipmentService equipmentService)
        {
            if (equipmentService.CanEquip(this, weapon))
            {
                WeaponId = weapon.Id;
            }
            else
            {
                throw new IllegalArgumentException("Cannot Equip: " + weapon.Name);
            }
        }

        public void LevelUp()
        {
            throw new NotImplementedException();
        }

        public bool CanLevelUp()
        {
            throw new NotImplementedException();
        }

        public void ReceiveExp(int exp)
        {
            EXP += exp;
            if (EXP > 100)
            {
                LevelUpEvent e = new LevelUpEvent(this);
                EventBus.Dispatch(e);
                EXP = 0;
            }
        }

        public Transform GetPosition()
        {
            return Position;
        }

        public Vector GetVelocity()
        {
            return Velocity;
        }

        public void MoveTo(long x, long y)
        {
            Position = new Transform(x, y);
        }

        public void StartMove(long velX, long velY)
        {
            Velocity = new Vector(velX, velY);
        }

        public void StopMove()
        {
            Velocity = Vector.ZERO;
        }

        public bool IsMoving()
        {
            return Velocity.X != 0 || Velocity.Y != 0;
        }
    }

    public class PlayerFactory
    {
        public static Player Create(string name, PlayerClass playerClass)
        {
            return new Player(PlayerId.New, name, playerClass);
        }
    }
}